# 1.函数的多个参数
# def sumMoreParam(num1, num2):
#     print(num1 + num2)
# sumMoreParam(2, 3)

# 2.函数的参数不定长参数
# 方式一参数前面增加一个*  表示参数就是元祖类型， 因为元祖有序不可变
# def mySum(*args):
#     print(args, type(args))
# mySum(1, 2, 3, 4)

# 方式二参数前面增加两个**  表示参数就是字典类型
# def mySum(**kwargs):
#     print(kwargs, type(kwargs))
# mySum(key1=1, key2=2, key3=3, key4=4)

# 装包：把传递来的参数，包装成一个集合的形式，比如元祖、字典
# 拆包：把集合的参数分解成个体
# def mySum(*args):
#     print(len(args), *args)  # 拆包
# mySum(1, 2, 3, 4)  # 装包

# def test(**kwargs):
#     print(kwargs['key'])  # 拆包
# test(key=1, a=2)  # 装包

# 3.函数的缺省参数，参数默认值
# def hate(somebody='凯尔'):
#     print('我想打', somebody)
# hate()


# 4.函数的注意事项 python里面只有地址传递（引用传递） 参数是可变的可以修改,  不可变的不能更改
# b = 10
# print('b之前地址---', id(b), b)
# def change(num):
#     num = num + 2
#     print('num的地址-----', id(num), num)
# change(b)
# print('b之后地址---', id(b), b)

# 参数是可变的可以修改
# b = [1, 3, 4]
# print('b之前地址---', id(b), b)
# def change(num):
#     num.append(4)
#     print('num的地址---', id(num), num)
# change(b)
# print('b之后地址---', id(b), b)

# 5.函数的使用说明
# def mySum(*args):
#     """
#     这里函数说明
#     """
#     pass

# 6. 偏函数
# # 方式一 ：自己创建这个函数就是一个偏函数
# def test1(a, b, c, d=1):
#     print(a + b + c + d)

# def test2(a, b, c=2, d=2):
#     test1(a, b, c, d)
#
# test2(1, 2)

# 方式二： 系统快速创建偏函数

# def test1(a, b, c, d=1):
#     print(a + b + c + d)
# import functools
#
# test3 = functools.partial(test1, c=2, d=2)
# test3(1, 2)

# 偏函数的使用场景
# import functools
# a = "10010"
# int2 = functools.partial(int, base=2)
# int10 = functools.partial(int, base=10)
# print(int2(a), int10(a))

# 7.高阶函数 - 函数作为另一个函数的参数
# 7.1 函数作为参数
# list = [{"name": 'lz', 'age': 18}, {"name": 'zlz', 'age': 34}, {"name": 'xlz', 'age': 27}]
# def getKey(item):
#     return item['age']
# result = sorted(list, key=getKey)
# print(result)

# 7.2 函数作为参数
# def computeNum(num1, num2, func):
#     print(func(num1, num2))
#
# def sum(num1, num2):
#     return num1 + num2
#
# def jian(num1, num2):
#     return num1 - num2
#
# computeNum(6, 2, sum)
# computeNum(6, 2, jian)

# 8. 返回函数
# def computeFunc(flag):
#     def __sum(a, b):
#         return a + b
#     def __jian(a, b):
#         return a - b
#
#     if flag == '+':
#         return __sum
#     else:
#         return __jian
# getFunc = computeFunc('+')
# print(getFunc(1, 2))

# 9. 匿名函数 - lambda函数  没有return  :之后的表达式就是返回值
# print((lambda x, y: x + y)(1, 2))
#
# noname = lambda x, y: x * y
# print(noname(2, 4))
#
# list = [{"name": 'lz', 'age': 18}, {"name": 'zlz', 'age': 34}, {"name": 'xlz', 'age': 27}]
# result = sorted(list, key=lambda item: item['age'])
# print(result)

# 9. 闭包  在函数嵌套的条件下，内层函数引用外包变量， 内层函数左右外部函数的返回值
# def outerFunc(a):
#     def innerFunc(b):
#         print(a + b)
#     return innerFunc
# newFunc = outerFunc(10)
# newFunc(2)

# 9.1 应用场景 外层函数根据不同参数，生成不同功能的函数
# def line_config(content, length):
#      def line(str):
#          print(str * (length // 2) + content + str * (length // 2))
#      return line
#
# createLine = line_config('abc', 40)
# createLine("+")
# createLine("-")
# createLine("=")

# # 9.2 闭包注意事项 修改外部变量 nonlocal  申明非局部的num
# def outerFunc():
#     num = 10
#     def innerFunc():
#         nonlocal num
#         num = 23
#         print('内层的---', num)
#     innerFunc()
#     print('外层的---', num)
#     return innerFunc
# newFunc = outerFunc()
# newFunc()

# 9.2 闭包注意事项 函数的内部变量参数对应的值是在函数调用时候确定
# def outterFunc():
#     funs = []
#     for i in range(1, 4):
#         def innerFunc():
#             print(i)
#         funs.append(innerFunc)
#     return funs
# newFuncs = outterFunc()
# newFuncs[0]()
# newFuncs[1]()
# newFuncs[2]()
# '''
# 结果
# 3
# 3
# 3
# '''

# def outterFunc():
#     funs = []
#     for i in range(1, 4):
#         def innerFunc(i):
#             def innerFunc2():
#                 print(i)  # 属于某一个函数 并保存在列表中啦
#             return innerFunc2
#         funs.append(innerFunc(i))
#     return funs
# newFuncs = outterFunc()
# newFuncs[0]()
# newFuncs[1]()
# newFuncs[2]()
# '''
# 结果
# 1
# 2
# 3
# '''

# 10. 装饰器 - 扩充函数的功能

# 10.1 发说说之前验证是否已经登录
# def checkLogin(func):
#
#     def innerFunc():
#         print('验证登录成功---')
#         func()  # 执行函数
#     return innerFunc
#
# def sendText():
#     print('发说说-----')
#
#
# def sendImage():
#     print('发图片----')
#
# sendText = checkLogin(sendText)
# sendImage = checkLogin(sendImage)
# index = 1
# if index == 1:
#     sendText()
# else:
#     sendImage()


# 10.2. 闭包使用发说说之前验证是否已经登录 - 闭包语法糖
# def checkLogin(func):
#     def innerFunc():
#         print('验证登录成功---')
#         func()  # 执行函数
#     return innerFunc
#
# @checkLogin      # sendText = checkLogin(sendText)就相当于@checkLogin
# def sendText():
#     print('发说说-----')
# @checkLogin     # sendImage = checkLogin(sendImage)就相当于@checkLogin
# def sendImage():
#     print('发图片----')
#
# index = 1
# if index == 1:
#     sendText()
# else:
#     sendImage()

# 10.3 闭包的注意事项
#  A. 装饰器函数是在被装饰函数执行的时候才会执行
#  B. 被装饰函数有几个参数，那么闭包内部函数该有几个参数
#  C. 多个装饰器，从上到下装饰，执行也是
#  D. 通用装饰器一般都是不定长参数 *args (元祖) **kwargs （字典）
#  E. 装饰器函数是在被装饰函数格式必须统一， 有返回值就都有返回值
#  F. 带有参数的装饰器

# def checkLogin(func):
#     def innerFunc(name, count):
#         print('验证登录成功---')
#         func(name, count)  # 执行函数
#     return innerFunc
#
# @checkLogin      # sendText = checkLogin(sendText)就相当于@checkLogin
# def sendText(name, count):
#     print(name + '发说说-----' + str(count))
# @checkLogin     # sendImage = checkLogin(sendImage)就相当于@checkLogin
# def sendImage(name, count):
#     print(name + '发图片----' + str(count))
#
# index = 1
# if index == 1:
#     sendText('刘子彬', 6)
# else:
#     sendImage('冯大眼', 10)

# def print_line(func):
#     def inner():
#         print('-' * 30)
#         func()
#     return inner
#
# def print_star(func):
#     def inner():
#         print('*' * 30)
#         func()
#     return inner
#
# @print_star
# @print_line
# def sendText():
#     print('打出子弹-----')
#
# sendText()


#  D. 通用装饰器一般都是不定长参数 *args (元祖) **kwargs （字典）
# def checkLogin(func):
#     def innerFunc(*args, **kwargs):
#         print('验证登录成功---', *args, **kwargs)
#         # 解包
#         func(*args, **kwargs)  # 执行函数
#     return innerFunc
#
# @checkLogin      # sendText = checkLogin(sendText)就相当于@checkLogin
# def sendText(name, count):
#     print(name + '发说说-----' + str(count))
# @checkLogin     # sendImage = checkLogin(sendImage)就相当于@checkLogin
# def sendImage(name):
#     print(name + '发图片----')
#
# index = 2
# if index == 1:
#     sendText('刘子彬', 6)
# else:
#     sendImage('冯大眼')


#  E. 装饰器函数是在被装饰函数格式必须统一， 有返回值就都有返回值

# def checkLogin(func):
#     def innerFunc(*args, **kwargs):
#         print('验证登录成功---', *args, **kwargs)
#         # 解包
#         return func(*args, **kwargs)  # 执行函数
#     return innerFunc
#
# @checkLogin      # sendText = checkLogin(sendText)就相当于@checkLogin
# def sendText(name, count):
#     print(name + '发说说-----' + str(count))
#     return name + '返回'
# @checkLogin     # sendImage = checkLogin(sendImage)就相当于@checkLogin
# def sendImage(name):
#     print(name + '发图片----')
#     return name + '返回'
#
# index = 2
# if index == 1:
#     result = sendText('刘子彬', 6)
#     print(result)
# else:
#     result = sendImage('李二')
#     print(result)


#  F. 带有参数的装饰器 - 多装饰器函数再一次装饰

# def getzsq(char):
#     def zsq_print(func):
#         def inner(*args, **kwargs):
#             print(char * 30)
#             return func(*args, **kwargs)
#         return inner
#     return zsq_print
#
# @getzsq("=")
# def print_content():
#     print('0000000')
#
# print_content()

# 11. 生成器 （特殊的迭代器） 惰性加载（列表一个一个加载到内存）、可迭代 ， next() 查状态
# 11.1 生成器创建方式
# 方式一 列表推导式 []  -> （）
# l = [i for i in range(1, 100000000000000) if i % 2 == 0]  # 数据量大 卡顿 必须使用生成器处理
# l = (i for i in range(1, 100000000000000) if i % 2 == 0)  # 不卡顿
# print(next(l))
# print(l.__next__())
# for i in l:
#     print(i)

# 方式二 生成器函数 必须包含 yield  yield 后面是状态 状态指针指向点  next()一只调用有可能溢出
# def test():
#      print('1 - 状态之前')
#      yield 1
#      print('a')
#
#      yield 2
#      print('b')
#
#      yield 3
#      print('c')
# g = test()  # 生成一个生成器, 不执行函数
# print(g)
# print(next(g))
# print(next(g))
# print(next(g))

# 11.2 生成器的操作方法 send函数传参， send 为上一次yield1的返回值传值 yield返回的状态， 第一次不能调用非空值
# def test():
#     yield1 = yield 1   # (yield 1) == send里面的参数
#     print(yield1)
#
#     yield2 = yield 2
#     print(yield2)
# g = test()
# print(next(g))
# print(g.send('aaa'))
# g.close()   # 关闭生成器方法 关闭之后不能访问啦

# 11.3 生成器的注意事项
# 生成器有return返回值： 抛出异常 返回return的值  后面代码不执行
# 生成器 就像迭代器一样 只能被遍历一次 要想多次重新创建生成器

# def test():
#     yield1 = yield 1   # (yield 1) == send里面的参数
#     print(yield1)
#     return 10    # 抛出异常
#
#     yield2 = yield 2
#     print(yield2)
# g = test()
# print(next(g))
# print(g.send('aaa'))


# def test():
#     yield 1   # (yield 1) == send里面的参数
#     print('aaaaaaa')
#     yield 2
#     print('bbbbbb')
# g = test()
# for i in g:
#     print(i)
#
# gg = test()
# for i in gg:
#     print(i)



















